package com.ibm.cloud.banking.trans.account;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ibm.cloud.banking.account.entity.AccountInfo;
import com.ibm.cloud.banking.facade.account.IAccountFacade;
import com.ibm.cloud.banking.facade.account.dto.AccountBalanceUpdateDTO;
import com.ibm.cloud.banking.facade.account.dto.AccountInfoDTO;
import com.ibm.cloud.banking.facade.customer.ICustomerCommandFacade;
import com.ibm.cloud.banking.facade.customer.dto.CustAcctRelDTO;
import com.ibm.cloud.banking.facade.customer.dto.CustomerAccountRelDTO;
import com.ibm.cloud.banking.facade.media.IMediaCardFacade;
import com.ibm.cloud.banking.facade.media.dto.MediaCardDTO;
import com.ibm.cloud.banking.parameter.pricing.entity.*;
import com.ibm.cloud.banking.parameter.pricing.service.PricingChargingInnerServiceImpl;
import com.ibm.cloud.banking.platform.message.RequestHeader;
import com.ibm.cloud.banking.prod.dto.ProductCheckDTO;
import com.ibm.cloud.banking.prod.service.ProductParameterQueryServiceImpl;
import com.ibm.cloud.banking.trans.account.dto.Req111225;
import com.ibm.cloud.banking.trans.account.dto.Resp111225;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spi.Synchronization;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Configuration
public class Trans111225 extends RouteBuilder {

    @Autowired
    ProductParameterQueryServiceImpl productParameterQueryServiceImpl;

    @Autowired
    ICustomerCommandFacade customerCommandFacade;

    @Autowired
    IAccountFacade accountFacade;

    @Autowired
    IMediaCardFacade mediaCardFacade;

    @Autowired
    PricingChargingInnerServiceImpl pricingChargingInnerServiceImpl;

    private static final String ORIGINAL_REQUEST_BODY_KEY = "ORIGINAL-REQUEST-BODY";

    ObjectMapper mapper = new ObjectMapper();

    String PCS_CODE = "T20";
    String ROUTE_URI = "direct:T20";
    String ROUTE_DESC = "开户交易T20";
    String ROUTE_ID = "PCS-FLOW-T20";

    String CHECK_PRODUCT_AVAILABLE = "direct:410";
    String CHECK_PRODUCT_CONDITION = "direct:411";
    String CUST_PRODUCT_ACCTS = "direct:412";
    String CUST_PRODUCT_EFFECTIVE_ACCTS_COUNT = "direct:413";
    String SAVING_CUSTOMER_ACCOUNT = "direct:414";
    String SAVING_CUSTOMER_ACCOUNT_REL = "direct:415";
    String UPDATE_ACCOUNT_BALANCE = "direct:416";
    String ALLOCATE_MEDIA_CARD = "direct:417";
    String SEND_OPEN_ACCOUNT_MSG = "direct:418";
    String PRICING_CHARGING_SERVICE = "direct:419";



    @Override
    public void configure() throws Exception {

        from(ROUTE_URI)
                .routeDescription(ROUTE_DESC)
                .routeId(ROUTE_ID)
                .log("开始执行开户交易。")
                .to(CHECK_PRODUCT_AVAILABLE)
                .to(CHECK_PRODUCT_CONDITION)
                .to(CUST_PRODUCT_ACCTS)
                .to(CUST_PRODUCT_EFFECTIVE_ACCTS_COUNT)
//                .saga()
//                .timeout(1, TimeUnit.MINUTES)
//                .propagation(SagaPropagation.REQUIRES_NEW)  //使用 exchange 的同步补偿
                .to(SAVING_CUSTOMER_ACCOUNT)
                .to(SAVING_CUSTOMER_ACCOUNT_REL)
                .to(UPDATE_ACCOUNT_BALANCE)
                .to(ALLOCATE_MEDIA_CARD)
                .to(SEND_OPEN_ACCOUNT_MSG)
                .to(PRICING_CHARGING_SERVICE)
                .log("开户交易执行结束");

        //1.检验产品信息
        //1.1 校验产品可售信息
        from(CHECK_PRODUCT_AVAILABLE)
                .process(exchange -> {
                    Map<String, Object> requestMsg = (LinkedHashMap<String, Object>)exchange.getIn().getBody();
                    //// 缓存源始请求报文体
                    exchange.setProperty(ORIGINAL_REQUEST_BODY_KEY,mapper.readValue(mapper.writeValueAsString(requestMsg), Req111225.class));

                    String productNo = (String)requestMsg.get("productNo");
                    // Object[] params = new Object[]{productNo,new Date()};
                    // exchange.getIn().setBody(params, Object[].class);
                    ProductCheckDTO params = new ProductCheckDTO();
                    params.setProductNo(productNo);
                    params.setTransDate(new Date());
                    exchange.getIn().setBody(params, ProductCheckDTO.class);
                })
                .bean(productParameterQueryServiceImpl, "checkProductAvailable").log("检查产品可售信息");

        //1.2 校验产品条件信息
        from(CHECK_PRODUCT_CONDITION)
                .process(exchange -> {
                    Req111225 requestMsg = (Req111225)exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY);
                    ProductCheckDTO params = new ProductCheckDTO();
                    params.setProductNo(requestMsg.getProductNo());
                    params.setAmount(requestMsg.getTransAmount().doubleValue());
                    params.setAccountCategory(requestMsg.getAccountCategory());
                    params.setType(1);
                    exchange.getIn().setBody(params, ProductCheckDTO.class);
                })
                .bean(productParameterQueryServiceImpl, "checkAcctProduct").log("检查产品条件信息");

        //2.客户账户信息查询，同客户同产品下所有账户信息（客户领域）
        from(CUST_PRODUCT_ACCTS)
                .process(exchange -> {
                    Req111225 requestMsg = (Req111225)exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY);
                    CustomerAccountRelDTO params = new CustomerAccountRelDTO();
                    params.setProductNo(requestMsg.getProductNo());
                    params.setCustomerNo(requestMsg.getCustomerNo());
                    params.setAccountCategory(requestMsg.getAccountCategory());
                    exchange.getIn().setBody(params, CustomerAccountRelDTO.class);
                })
                .bean(customerCommandFacade, "getCustSingleProductAccts").log("获取客户该产品已开账户信息");


        //3.客户账户状态验证，同客户同产品下有效账户统计，判断有效账户个数是否超过产品同一客户开户最大限制数（账户领域）
        from(CUST_PRODUCT_EFFECTIVE_ACCTS_COUNT)
                .process(exchange -> {
                    // 获取上一步结果
                    List<CustomerAccountRelDTO> customerAccountRels = exchange.getIn().getBody(List.class);
                    CustAcctRelDTO params = new CustAcctRelDTO();
                    List<CustAcctRelDTO> custAcctRels = new ArrayList<>();
                    Optional.ofNullable(customerAccountRels).ifPresent(action -> {
                        action.forEach(item -> {
                            CustAcctRelDTO dto = new CustAcctRelDTO();
                            BeanUtils.copyProperties(item,dto);
                            custAcctRels.add(dto);
                        });
                    });
                    params.setCustAcctRelList(custAcctRels);
                    params.setMaxAcctCount(1000);
                    exchange.getIn().setBody(params, CustAcctRelDTO.class);
                })
                .bean(accountFacade, "getSingleProductEffectiveAcctCnt").log("判断有效账户个数是否超限");

        //4.开立结算账户，保存客户购买产品账号（账户领域）
        from(SAVING_CUSTOMER_ACCOUNT)
                .process(exchange -> {
                    Req111225 requestMsg = (Req111225)exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY);
                    RequestHeader header = exchange.getIn().getHeader("reqHeader",RequestHeader.class);
                    AccountInfoDTO accountInfoDTO = new AccountInfoDTO();
                    BeanUtils.copyProperties(requestMsg, accountInfoDTO);
                    accountInfoDTO.setInitialDate(new Date());
                    accountInfoDTO.setInitialTellerId(header.getTxnTlrCod());
                    accountInfoDTO.setInitialChannel(header.getChannel());
                    // todo 账号可调用序号组件生成
                    accountInfoDTO.setAccountNo(UUID.randomUUID().toString());
                    // todo 交易流水调用业务流水号生成组件生成
                    accountInfoDTO.setTransNo(UUID.randomUUID().toString());
                    exchange.getIn().setBody(accountInfoDTO, AccountInfoDTO.class);
                    exchange.getUnitOfWork().addSynchronization(new Synchronization() {
                        @Override
                        public void onComplete(Exchange exchange) {

                        }

                        @Override
                        public void onFailure(Exchange exchange) {
                            // 补偿逻辑
                            accountFacade.deleteAccount(accountInfoDTO.getAccountNo());
                        }
                    });
                })
                .bean(accountFacade, "savingCustAcct").log("开立结算账户");

        //5.登记客户账户（客户领域）
        from(SAVING_CUSTOMER_ACCOUNT_REL)
                .process(exchange -> {
                    Req111225 requestMsg = (Req111225)exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY);
                    // 获取上一步保存账户信息
                    AccountInfoDTO accountInfoDTO = exchange.getIn().getBody(AccountInfoDTO.class);
                    exchange.setProperty("account-detail",accountInfoDTO);
                    CustomerAccountRelDTO custAcctRel = new CustomerAccountRelDTO();
                    BeanUtils.copyProperties(requestMsg, custAcctRel);
                    BeanUtils.copyProperties(accountInfoDTO, custAcctRel);
                    custAcctRel.setCreateTellerId(accountInfoDTO.getInitialTellerId());
                    custAcctRel.setAccountInitialDate(accountInfoDTO.getInitialDate());
                    custAcctRel.setAccountBranch(accountInfoDTO.getInitialBranch());
                    custAcctRel.setName(accountInfoDTO.getCustomerName());
                    exchange.getIn().setBody(custAcctRel, CustomerAccountRelDTO.class);
                    exchange.getUnitOfWork().addSynchronization(new Synchronization() {
                        @Override
                        public void onComplete(Exchange exchange) {

                        }

                        @Override
                        public void onFailure(Exchange exchange) {
                            // 补偿逻辑
                            customerCommandFacade.deleteCustAcctRel(custAcctRel);
                        }
                    });
                })
                .bean(customerCommandFacade, "savingCustAcctRel").log("异步登记客户账户");

        //6.更新账户余额和账户明细（账户领域）
        from(UPDATE_ACCOUNT_BALANCE)
                .process(exchange -> {
                    Req111225 requestMsg = (Req111225)exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY);
                    // 获取上一步保存账户信息
                    AccountInfoDTO accountInfoDTO = exchange.getProperty("account-detail",AccountInfoDTO.class);
                    AccountBalanceUpdateDTO paramsDto = new AccountBalanceUpdateDTO();
                    BeanUtils.copyProperties(requestMsg, paramsDto);
                    paramsDto.setAccountNo(accountInfoDTO.getAccountNo());
                    paramsDto.setBalance(requestMsg.getTransAmount());
                    paramsDto.setOperatorTellerId(accountInfoDTO.getInitialTellerId());
                    paramsDto.setInitiationChannelNo(accountInfoDTO.getInitialChannel());
                    paramsDto.setTransCode("T20");
                    paramsDto.setTransNo(accountInfoDTO.getTransNo());
                    // 开户时为账户存入
                    paramsDto.setDeposit(true);
                    paramsDto.setReverseFlag(AccountInfo.REVERSE_FLAG_NORMAL);
                    paramsDto.setTransDate(accountInfoDTO.getInitialDate());
                    paramsDto.setTransTime(accountInfoDTO.getInitialDate());
                    exchange.getIn().setBody(paramsDto, AccountBalanceUpdateDTO.class);
                    exchange.getUnitOfWork().addSynchronization(new Synchronization() {
                        @Override
                        public void onComplete(Exchange exchange) {

                        }

                        @Override
                        public void onFailure(Exchange exchange) {
                            // 补偿逻辑
                            accountFacade.acctTransferInRefund(paramsDto);
                        }
                    });
                })
                .bean(accountFacade, "acctTransferIn").log("更新账户余额和账户明细");

        //7.配发介质(介质领域)
        from(ALLOCATE_MEDIA_CARD)
                .process(exchange -> {
                    Req111225 requestMsg = (Req111225)exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY);
                    // 获取上一步保存账户信息
                    AccountInfoDTO accountInfoDTO = exchange.getProperty("account-detail",AccountInfoDTO.class);
                    MediaCardDTO mediaCardDTO = new MediaCardDTO();
                    mediaCardDTO.setCardNo(requestMsg.getMainCardNo());
                    mediaCardDTO.setCustomerNo(requestMsg.getCustomerNo());
                    mediaCardDTO.setOpenDate(accountInfoDTO.getInitialDate());
                    mediaCardDTO.setTransTellerId(accountInfoDTO.getInitialTellerId());
                    mediaCardDTO.setPassword(requestMsg.getPassword());
                    mediaCardDTO.setProductNo(requestMsg.getProductNo());
                    mediaCardDTO.setLevel(requestMsg.getCardLevel().toString());
                    mediaCardDTO.setType(requestMsg.getAccountCategory());
                    mediaCardDTO.setAccountNo(accountInfoDTO.getAccountNo());
                    exchange.getIn().setBody(mediaCardDTO, MediaCardDTO.class);
                    exchange.getUnitOfWork().addSynchronization(new Synchronization() {
                        @Override
                        public void onComplete(Exchange exchange) {

                        }

                        @Override
                        public void onFailure(Exchange exchange) {
                            // 补偿逻辑
                            mediaCardFacade.allocateMediaCardRefund(mediaCardDTO);
                        }
                    });
                })
                .bean(mediaCardFacade, "allocateMediaCard").log("配发介质");

        // 8.发送动户通知
        from(SEND_OPEN_ACCOUNT_MSG)
                .log("发送动户通知");

        // 9.记录核算流水

        //10.计算手续费
        from(PRICING_CHARGING_SERVICE)
                .process(new CountServiceChargeProcessor())
                .bean(pricingChargingInnerServiceImpl, "pricingChargingService")
                .process(new Processor() {
                    @Override
                    public void process(Exchange exchange) throws Exception {
                        AccountInfoDTO accountInfoDTO = exchange.getProperty("account-detail",AccountInfoDTO.class);
                        Req111225 requestMsg = (Req111225)exchange.getProperty(ORIGINAL_REQUEST_BODY_KEY);
                        Resp111225 response = new Resp111225();
                        BeanUtils.copyProperties(accountInfoDTO, response);
                        response.setCardNo(requestMsg.getMainCardNo());
                        exchange.getIn().setBody(response, Resp111225.class);
                    }
                })
                .log("计算转账手续费");

    }

    class CountServiceChargeProcessor implements Processor{

        @Override
        public void process(Exchange exchange) throws Exception {
            // 定义入参对象
            PricingChargeParamVo pricingChargeParamVo = new PricingChargeParamVo();
            // 计收费标志
            pricingChargeParamVo.setChargeFlag(1);
            // 计费资料
            JiFeiItemVo jiFeiItemVo = new JiFeiItemVo();
            jiFeiItemVo.setBillgCcyCode("156");
            jiFeiItemVo.setChbz("1");
            jiFeiItemVo.setPzzl("");
            pricingChargeParamVo.setJiFeiItemVo(jiFeiItemVo);
            FeeCurrenyCodeVo feeCurrenyCodeVo = new FeeCurrenyCodeVo(); // 费种信息
            feeCurrenyCodeVo.setFeeCode("0000000015");
            feeCurrenyCodeVo.setTransAmount(new BigDecimal("0"));
//        	feeCurrenyCodeVo.setTransAmount(new BigDecimal("10000"));
            feeCurrenyCodeVo.setNum(1);
//        	feeCurrenyCodeVo.setDuctPointVal(new BigDecimal("1000"));
            feeCurrenyCodeVo.setDuctPointVal(new BigDecimal("0"));
            feeCurrenyCodeVo.setTransCcyCode("156");
            feeCurrenyCodeVo.setHasDuctPointVal(new BigDecimal("0"));
//        	feeCurrenyCodeVo.setHasDuctPointVal(new BigDecimal("1000"));
            feeCurrenyCodeVo.setChargeZjSeq(Integer.parseInt("12345"));
            pricingChargeParamVo.setFeeCurrenyCodeVo(feeCurrenyCodeVo);
            ShouFeiItemVo shouFeiItemVo = new ShouFeiItemVo(); // 收费资料
            shouFeiItemVo.setXzbz("1");
            shouFeiItemVo.setKkzh("123456");
            shouFeiItemVo.setSfAmount(new BigDecimal("500"));
            shouFeiItemVo.setSfCcyCode("156");
            shouFeiItemVo.setZzsFlag("0");
            pricingChargeParamVo.setShouFeiItemVo(shouFeiItemVo);
            BusinessSceneInfoVo businessSceneInfoVo = new BusinessSceneInfoVo(); // 业务场景信息
            businessSceneInfoVo.setTransCode("000001099");
            businessSceneInfoVo.setDgdsFlag("1");
            businessSceneInfoVo.setGbdm("CHN");
            businessSceneInfoVo.setJrjgbz("0");
//            businessSceneInfoVo.setCustNo(mediaCardDTO.getCustomerNo());
//            businessSceneInfoVo.setAccountNo(mediaCardDTO.getAccountNo());
            businessSceneInfoVo.setCustNo("000000001");
            businessSceneInfoVo.setAccountNo("99999152739623103214");
            businessSceneInfoVo.setAccountTypeCode("1");
            businessSceneInfoVo.setSaleProductNo("PD152739607487599776");
            businessSceneInfoVo.setProductHyCode("PD15273960748759977");
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
            String chargeStartDate = "20210101";
            try {
                Date startDate = dateFormat.parse(chargeStartDate);
                businessSceneInfoVo.setChargeStartDate(startDate);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            String chargeEndDate = "20210101";
            try {
                Date endDate = dateFormat.parse(chargeEndDate);
                businessSceneInfoVo.setChargeEndDate(endDate);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            businessSceneInfoVo.setChannelCode("00");
            businessSceneInfoVo.setTransOrgNo("801000006");
            businessSceneInfoVo.setDfOrgNo("801000004");
            businessSceneInfoVo.setDfAccountNo("99999152739623103215");
            businessSceneInfoVo.setFyslbh("1111");
            businessSceneInfoVo.setBatchChargeAmount(new BigDecimal("10"));
            businessSceneInfoVo.setBatchChargeNum(Integer.parseInt("1"));
            businessSceneInfoVo.setTransCurrencyCode("156");
            businessSceneInfoVo.setJyjzlx("1");
            businessSceneInfoVo.setJzh("123456789123456");
            Date date = new Date();
            String cmOperCode ="666001";//固定一个柜员号
            businessSceneInfoVo.setTransDate(date);
            businessSceneInfoVo.setTransTime("09:01:11");
            businessSceneInfoVo.setChannelCode("01");
            businessSceneInfoVo.setTransPersonCode(cmOperCode); // 柜员号
            pricingChargeParamVo.setBusinessSceneInfoVo(businessSceneInfoVo);
            // 收费因子,原有代码这块儿逻辑已注掉
            List<FeeYiZiItemVo> feeYiZiItemVoList = new ArrayList<FeeYiZiItemVo>();
            pricingChargeParamVo.setFeeYiZiItemVoList(feeYiZiItemVoList);
            // 差异维度数组
            List<ChaYiWeiDuItemVo> chaYiWeiDuItemVoList = new ArrayList<>();
            pricingChargeParamVo.setChaYiWeiDuItemVoList(chaYiWeiDuItemVoList);
            exchange.getIn().setBody(pricingChargeParamVo, PricingChargeParamVo.class);
        }
    }
}
